package org.luxor.cloud.gateway.config;

import org.luxor.cloud.gateway.component.security.*;
import org.luxor.cloud.gateway.service.DynamicRouteService;
import org.springframework.boot.autoconfigure.security.oauth2.resource.OAuth2ResourceServerProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.oauth2.server.resource.introspection.ReactiveOpaqueTokenIntrospector;
import org.springframework.security.oauth2.server.resource.web.server.ServerBearerTokenAuthenticationConverter;
import org.springframework.security.web.server.SecurityWebFilterChain;


/**
 * 网关资源权限配置
 *
 * @author Mr.Yan  @date: 2020/11/13
 */
@Configuration
@EnableWebFluxSecurity
@EnableConfigurationProperties({WebSecurityProperties.class, OAuth2ResourceServerProperties.class})
public class GatewaySecurityConfiguration {

    private WebSecurityProperties webSecurityProperties;
    private OAuth2ResourceServerProperties resourceServerProperties;
    private DynamicRouteService dynamicRouteService;

    public GatewaySecurityConfiguration(DynamicRouteService dynamicRouteService
            , OAuth2ResourceServerProperties resourceServerProperties
            , WebSecurityProperties webSecurityProperties) {
        this.dynamicRouteService = dynamicRouteService;
        this.webSecurityProperties = webSecurityProperties;
        this.resourceServerProperties = resourceServerProperties;
    }

    @Bean
    public ReactiveOpaqueTokenIntrospector introspect() {
        String introspectUri = resourceServerProperties.getOpaquetoken().getIntrospectionUri();
        String clientId = resourceServerProperties.getOpaquetoken().getClientId();
        String clientSecret = resourceServerProperties.getOpaquetoken().getClientSecret();
        return new OAuth2OpaqueTokenIntrospector(introspectUri, clientId, clientSecret);
    }

    @Bean
    public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
        ServerBearerTokenAuthenticationConverter bearerTokenConverter = new ServerBearerTokenAuthenticationConverter();
        bearerTokenConverter.setAllowUriQueryParameter(true);

        // 允许使用iframe 嵌套，避免swagger-ui 不被加载的问题
        http.headers().frameOptions().disable()
                .and().oauth2ResourceServer()
                .bearerTokenConverter(bearerTokenConverter)
                .opaqueToken().introspector(introspect()).and()
                .and().anonymous().principal(SecurityUtils.ANONYMUS)
                .and().authorizeExchange()
                .pathMatchers(webSecurityProperties.getAnonUris()).permitAll()
                .anyExchange().access(new OAuth2ReactiveAuthorizationManager(dynamicRouteService))
                .and().exceptionHandling()
                .authenticationEntryPoint(new HttpOAuth2ServerAuthenticationEntryPoint())
                .accessDeniedHandler(new HttpOAuth2ServerAccessDeniedHandler())
                .and().csrf().disable();

        return http.build();
    }
}
